package com.ihakul.logger;

import android.content.Context;

import androidx.annotation.NonNull;

import java.io.IOException;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * {@link LogBuilder.ILogger ILogger} {@code API Wrapper}，
 *
 * @author Aaron
 * @version 2.1
 * Create at 2019/7/17
 */
public final class IotLogger implements LogBuilder.ILogger {
    static final String ANDROID_HANDLER="com.android.internal.logging.AndroidHandler";


    @NonNull @Override
    public LogBuilder.IConfigure with(Context context) {
        return new Enhancer(context);
    }

    @Override
    public void setLevel(Level level) {
        Logger root = rootLogger();
        root.setLevel(level);

        Handler[] handlers=root.getHandlers();
        for (Handler h : handlers) {

            if(h instanceof BufferedFileHandler &&
          h.getErrorManager() instanceof RecordFilter)
          {

             ((RecordFilter)h.getErrorManager())
                  .addLowHandler((level.intValue()<Level.INFO.intValue())?
                          new LowHandler(level):null
                  );
          }
        }

    }

    static final class Enhancer implements LogBuilder.IConfigure, LogBuilder.Enhanceable
            , LogBuilder.Enhanceable2 {

        private final Context mContext;
        private CrashCatcher mCatcher;
        private Configurator mConfigure;

        Enhancer(Context context) {
            mContext = context;
        }

        @NonNull @Override
        public Enhanceable useProperties() {
            mConfigure=new Configurator(mContext,true);
            return this;
        }

        @NonNull @Override
        public Enhanceable2 useConfiguration() {
            mConfigure=new Configurator(mContext,false);
            return this;
        }

        @NonNull @Override
        public Enhanceable openBuffering() {
            mConfigure.buffering="true";
            return this;
        }

        @Override
        public Enhanceable addReporter(@NonNull SevereReporter reporter) {
            mConfigure.setReporter(reporter);return this;
        }

        @NonNull @Override
    public LogBuilder openCrashedTracker() {
        mCatcher =new CrashCatcher(mContext);
        return this;
    }

    @Override
    public void build() {
        String packageName = mContext.getPackageName();
        String process=mContext.getApplicationContext().toString();
        if (!process.equals(System.getProperty(packageName))) {
            System.setProperty(packageName, process);

            try {
                mConfigure.init(mCatcher);
            } catch (IOException e) {
                // try to log error (at least with system logging)
                if(!mConfigure.getHandler().put(e)){
                    e.printStackTrace();
                }
                mCatcher = null;
            }

            if (mCatcher != null) {
                mCatcher.start();
            }
        }

    }

        @NonNull @Override
        public Logger build(String tagName) {
            this.build();
            return Logger.getLogger(tagName);
        }

        @Override
        public void freed() {

            Logger root = rootLogger();
            Handler[] handlers=root.getHandlers();
            System.clearProperty(mContext.getPackageName());

            if (handlers.length > 1)
            {
                for (Handler h : handlers) {
                    if(!ANDROID_HANDLER.equals(
                            h.getClass().getName())){

                        /* remove log handler */
                        root.removeHandler(h);

                        if(h instanceof BufferedFileHandler)
                            ((BufferedFileHandler)h).sureFlush();
                        else h.flush();

                        h.close();
                    }
                    else h.setLevel(Level.INFO);
                }
            }
        }
    }

    static Logger rootLogger(){
        // the root logger is called "" in JUL
        return Logger.getLogger("");
    }

}
